﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

using Storm;
using Storm.Docking;
using Storm.Docking.Controls;
using Storm.Docking.Controls.Float;
using Storm.Docking.Visual;
using Storm.Docking.Visual.Drawing;
using Storm.TabControl;
using Storm.TabControl.Base;
using Storm.TabControl.Design;
using Storm.TabControl.Helpers;

namespace Storm.Docking
{
    /// <summary>
    /// Represents a window in which Controls can be docked
    /// and moved around. The docked Controls can be auto-
    /// hidden, and have more than one Control in one panel.
    /// </summary>
    public class DockPane
        : Panel
    {
        #region Fields

		private DockRenderer  renderer      = null;

        // Splitters.
        private DockSplitter leftSplitter   = null;
        private DockSplitter rightSplitter  = null;
        private DockSplitter topSplitter    = null;
        private DockSplitter bottomSplitter = null;

		private DockDropArea leftRect;
		private DockDropArea rightRect;
		private DockDropArea topRect;
		private DockDropArea bottomRect;

		private TabStrip  tabStrip     = null;
		private ImageList tabImageList = null;

		#region Events

		/// <summary>
		/// Occurs when a DockPane is docked inside the DockPane.
		/// </summary>
		public event DockEventHandler PanelDock;

		/// <summary>
		/// Occurs when a DockPane is set to float inside the DockPane.
		/// </summary>
		public event DockEventHandler PanelFloat;

		#endregion

		#endregion

		#region Properties

		/// <summary>
		/// Gets the ImageList that contains all the icons used by the DockTabs.
		/// </summary>
		[Browsable(false)]
		[Description("Gets the ImageList that contains all the icons used by the DockTabs.")]
		public ImageList TabImageList
		{
			get { return tabImageList; }
		}

		/// <summary>
		/// Gets or sets the DockPane's and its children's DockRenderer.
		/// </summary>
		[Browsable(false)]
		[Description("Gets or sets the DockPane's and its children's DockRenderer.")]
		public DockRenderer Renderer
		{
			get { return renderer; }
			set
			{
				renderer = value;

				// Update all of the DockPane's DockPanels' Renderers.
				// The DockPanels automatically update their children.

				foreach (Control control in this.Controls)
				{
					if (control is DockPanel)
						(control as DockPanel).Renderer = this.Renderer;
				}

				this.BackColor = this.Renderer.DockColorTable.PaneBackColor;
				this.Font      = this.Renderer.DockColorTable.PaneFont;

				tabStrip.BackColor = this.Renderer.DockColorTable.PaneTabbedDocumentBackColor;

				tabStrip.SelectedColorStart  = this.Renderer.DockColorTable.PaneTabSelectedStartColor;
				tabStrip.SelectedColorEnd    = this.Renderer.DockColorTable.PaneTabSelectedEndColor;
				tabStrip.SelectedBorderColor = this.Renderer.DockColorTable.PaneTabSelectedBorderColor;
				tabStrip.SelectedForeColor   = this.Renderer.DockColorTable.PaneTabSelectedForeColor;

				tabStrip.NormalColorStart  = this.Renderer.DockColorTable.PaneTabNormalStartColor;
				tabStrip.NormalColorEnd    = this.Renderer.DockColorTable.PaneTabNormalEndColor;
				tabStrip.NormalBorderColor = this.Renderer.DockColorTable.PaneTabNormalBorderColor;
				tabStrip.NormalForeColor   = this.Renderer.DockColorTable.PaneTabNormalForeColor;

				leftRect.Opacity   = this.Renderer.DockColorTable.PaneDockRectangleOpacity;
				rightRect.Opacity  = this.Renderer.DockColorTable.PaneDockRectangleOpacity;
				topRect.Opacity    = this.Renderer.DockColorTable.PaneDockRectangleOpacity;
				bottomRect.Opacity = this.Renderer.DockColorTable.PaneDockRectangleOpacity;

				leftRect.BackColor   = this.Renderer.DockColorTable.PaneDockRectangleColor;
				rightRect.BackColor  = this.Renderer.DockColorTable.PaneDockRectangleColor;
				topRect.BackColor    = this.Renderer.DockColorTable.PaneDockRectangleColor;
				bottomRect.BackColor = this.Renderer.DockColorTable.PaneDockRectangleColor;

				if (this.FindForm() is DockForm)
					(this.FindForm() as DockForm).Renderer = this.Renderer;
				
				this.Invalidate();
			}
		}

        /// <summary>
        /// Gets the left Splitter of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the left Splitter of the DockPane.")]
        public DockSplitter LeftSplitter
        {
            get { return leftSplitter; }
        }

        /// <summary>
        /// Gets the right Splitter of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the right Splitter of the DockPane.")]
        public DockSplitter RightSplitter
        {
            get { return rightSplitter; }
        }

        /// <summary>
        /// Gets the top Splitter of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the top Splitter of the DockPane.")]
        public DockSplitter TopSplitter
        {
            get { return topSplitter; }
        }

        /// <summary>
        /// Gets the bottom Splitter of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the bottom Splitter of the DockPane.")]
        public DockSplitter BottomSplitter
        {
            get { return bottomSplitter; }
        }

        /// <summary>
        /// Gets the left dock Rectangle of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the left dock Rectangle of the DockPane.")]
		public DockDropArea LeftRect
        {
            get { return leftRect; }
        }

        /// <summary>
        /// Gets the right dock Rectangle of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the right dock Rectangle of the DockPane.")]
        public DockDropArea RightRect
        {
            get { return rightRect; }
        }

        /// <summary>
        /// Gets the top dock Rectangle of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the top dock Rectangle of the DockPane.")]
		public DockDropArea TopRect
        {
            get { return topRect; }
        }

        /// <summary>
        /// Gets the bottom dock Rectangle of the DockPane.
        /// </summary>
        [Browsable(false)]
        [Description("Gets the bottom dock Rectangle of the DockPane.")]
		public DockDropArea BottomRect
        {
            get { return bottomRect; }
        }

		#endregion

		#region Methods

		#region Public

		/// <summary>
		/// Creates a new DockPanel and adds the specified Form to it.
		/// </summary>
		/// <param name="form">Form to add to the DockPanel.</param>
		/// <param name="dockStyle">Where to dock the DockPanel.</param>
		/// <returns>The created DockPanel.</returns>
		public DockPanel CreatePanel(Form form, DockStyle dockStyle)
		{
            // Initialize a new DockPanel so we can add it 
            // to the DockPanel's Controls.

			DockPanel dockPanel = new DockPanel();

            // Setup the newly initialized DockPanel.

			dockPanel.DockPane = this;
			dockPanel.Dock = dockStyle;
			dockPanel.Form = form;
			dockPanel.Renderer = this.Renderer;

            // Holds whether to add the DockPanel to the
            // DockPane or not.

            bool controlAdd = true;

            // Check whether another DockPanel already is 
            // docked at the specified side.

            foreach (Control control in this.Controls)
            {
                if (control is DockPanel)
                {
                    DockPanel panel = control as DockPanel;
                    if (panel.Dock == dockStyle)
                    {
                        dockPanel.Controls.Remove(dockPanel.DockTab);
						dockPanel.MainDockTab = panel.DockTab;
                        panel.DockTab.TabPages.Add(dockPanel.
                            MainTabPage);

                        // Since the DockPanel has now been
                        // added to the already docked Dock-
                        // Panel, we want to remove it.

                        controlAdd = false;

                        // And finally break out of the loop.

                        break;
                    }
                }
            }

            // Add the DockPanel to the collection
            // of Controls in the DockPane.

            if (controlAdd == true)
                this.Controls.Add(dockPanel);

            this.PositionSplitters();   // Update the positions
                                        // of the Splitters.

			// Update the icons of the added Forms.

			this.UpdateIcons();

			// Finally return our created DockPanel.

			return dockPanel;
		}

		/// <summary>
		/// Creates and adds a tabbed document to the DockPane.
		/// </summary>
		/// <param name="form">Form that should be added as a tabbed document.</param>
		public TabStripItem CreateTabbedDocument(Form form)
		{
			// Setup the given Form so it can act as we want it to as a
			// tabbed document.

			form.Dock = DockStyle.Fill;
			form.TopLevel = false;
			form.FormBorderStyle = FormBorderStyle.None;

			TabStripItem item = new TabStripItem(form.Text, form);
			tabStrip.AddTab(item, true);

			return item;
		}

		/// <summary>
		/// Removes the given DockPanel from the DockPane.
		/// </summary>
		/// <param name="dockPanel">DockPanel to remove from the DockPane.</param>
		public void RemovePanel(DockPanel dockPanel)
		{
			// This is a wrapper.
			dockPanel.MakeClosed();
		}

		/// <summary>
		/// Removes the given Form from the DockPane's tabbed documents.
		/// </summary>
		/// <param name="form">Form to remove.</param>
		public void RemoveTabbedDocument(Form form)
		{
			TabStripItem tabStripItem = null;
			foreach (TabStripItem item in tabStrip.Items)
			{
				foreach (Control control in item.Controls)
				{
					if (control is Form && control == form)
					{
						tabStripItem = item;
						break;
					}
				}
			}

			if (tabStripItem != null)
				tabStrip.RemoveTab(tabStripItem);
		}

		/// <summary>
		/// Updates the icons of all the DockPanels' TabPages.
		/// </summary>
		public void UpdateIcons()
		{
			foreach (Control control in this.Controls)
			{
				if (control is DockPanel)
				{
					DockPanel dockPanel = control as DockPanel;
					foreach (TabPage page in dockPanel.DockTab.TabPages)
					{
						foreach (Control xcontrol in page.Controls)
						{
							if (xcontrol is DockContainer)
							{
								DockContainer container = xcontrol as DockContainer;
								this.TabImageList.Images.Add(container.Form.Text, container.Form.Icon);
								page.ImageIndex = this.TabImageList.Images.IndexOfKey(container.Form.Text);
							}
						}
					}
				}
			}
		}

		#endregion

        #region Internal

        /// <summary>
        /// Updates how the Splitters are docked.
        /// </summary>
        internal void PositionSplitters()
        {
            foreach (Control control in this.Controls)
            {
                if (control is DockPanel)
                {
                    DockPanel dockPanel = control as DockPanel;
                    if (dockPanel.Dock == DockStyle.Left)
                        this.LeftSplitter.Visible = true;
                    else if (dockPanel.Dock == DockStyle.Right)
                        this.RightSplitter.Visible = true;
                    else if (dockPanel.Dock == DockStyle.Top)
                        this.TopSplitter.Visible = true;
                    else if (dockPanel.Dock == DockStyle.Bottom)
                        this.BottomSplitter.Visible = true;
                }
            }
        }

        /// <summary>
        /// Updates the positions of the dock Rectangles to match
        /// the DockPane's location and size.
        /// </summary>
        internal void PositionDockRectangles()
        {
			Rectangle leftRect   = new Rectangle(0, 0, 50, this.Height);
			Rectangle rightRect  = new Rectangle(this.Width - 50, 0, 50, this.Height);
			Rectangle topRect    = new Rectangle(0, 0, this.Width, 50);
			Rectangle bottomRect = new Rectangle(0, this.Height - 50, this.Width, 50);

			this.LeftRect.Bounds   = this.RectangleToScreen(leftRect);
			this.RightRect.Bounds  = this.RectangleToScreen(rightRect);
			this.TopRect.Bounds    = this.RectangleToScreen(topRect);
			this.BottomRect.Bounds = this.RectangleToScreen(bottomRect);
        }

        /// <summary>
        /// Shows the docking Rectangles to the user.
        /// </summary>
        internal void ShowDockRectangles()
		{
			leftRect.Show();
			rightRect.Show();
			topRect.Show();
			bottomRect.Show();
        }

        /// <summary>
        /// Hides the docking Rectangles.
        /// </summary>
        internal void HideDockRectangles()
        {
			leftRect.Hide();
			rightRect.Hide();
			topRect.Hide();
			bottomRect.Hide();
        }

		/// <summary>
		/// Raises the Dock event.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">EventArgs.</param>
		internal virtual void OnDock(object sender, DockEventArgs e)
		{
			if (this.PanelDock != null)
				this.PanelDock(sender, e);
		}

		/// <summary>
		/// Raises the Float event.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">EventArgs.</param>
		internal virtual void OnFloat(object sender, DockEventArgs e)
		{
			if (this.PanelFloat != null)
				this.PanelFloat(sender, e);
		}

        #endregion

        #region Protected

        protected override void OnResize(EventArgs eventargs)
        {
            this.PositionDockRectangles();  // Update.
            base.OnResize(eventargs);
        }

        #endregion

        #endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="DockPane"/> class.
		/// </summary>
        public DockPane()
        {
			// Initialize the ImageList we use for added
			// Forms' icons in their tabs.

			tabImageList = new ImageList();

			// Initialize the TabStrip that contains
			// tabbed documents.

			tabStrip = new TabStrip();
			tabStrip.Dock = DockStyle.Fill;

			this.Controls.Add(tabStrip);

			// Initialize the DockDropAreas.

			leftRect = new DockDropArea();
			rightRect = new DockDropArea();
			topRect = new DockDropArea();
			bottomRect = new DockDropArea();

			// Initialize the Renderer, which automatically
			// updates all displayed Controls.

			this.Renderer = new DockRenderer();

            // Setup our Splitters.

            leftSplitter   = new DockSplitter();
            rightSplitter  = new DockSplitter();
            topSplitter    = new DockSplitter();
            bottomSplitter = new DockSplitter();

            this.LeftSplitter.Dock   = DockStyle.Left;
            this.RightSplitter.Dock  = DockStyle.Right;
            this.TopSplitter.Dock    = DockStyle.Top;
            this.BottomSplitter.Dock = DockStyle.Bottom;

            this.LeftSplitter.Visible = false;
            this.RightSplitter.Visible = false;
            this.TopSplitter.Visible = false;
            this.BottomSplitter.Visible = false;

            this.Controls.Add(this.LeftSplitter);
            this.Controls.Add(this.RightSplitter);
            this.Controls.Add(this.TopSplitter);
            this.Controls.Add(this.BottomSplitter);

            this.PositionDockRectangles();  // Update.
        }
    }
}
